
/****
 * Copyright (C) 2006 @authors
 *                                                            ****
 * This program is free software; you can redistribute it and/or *
 * modify under the terms of the GNU General Public License as   *
 * published by the Free Software Foundation;                    *
 * either version 2 of the License.                              *
 *                                                               *
 * This program is distributed in the hope that it will be       *
 * useful, but WITHOUT ANY WARRANTY; without even the implied    *
 * warranty of without even the implied waranty of               *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.          *
 * See the GNU General Public License for more details.          *
 *                                                               *
 * You should have received a copy of the                        *
 * GNU General Public License                                    *
 * along with this program; if not, write to the                 *
 * Free Software Foundation, Inc.,                               *
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. *
 *                                                               *
 ****                                                         ****/

#include "dcore.h"

void
d_process_pipe_init(d_process_t *process)
{
  process->pipeStdOut[0] = -1;
  process->pipeStdOut[1] = -1;
  process->pipeStdErr[0] = -1;
  process->pipeStdErr[1] = -1;
  process->pipeStdIn[0] = -1;
  process->pipeStdIn[1] = -1;
}

void
d_process_pipe_make(d_process_t *process)
{
  pipe(process->pipeStdOut);
  pipe(process->pipeStdErr);
  pipe(process->pipeStdIn);
}

void
d_process_pipe_close_unused(d_process_t *process)
{
  //son && error
  if (process->pid == 0 || process->pid == -1) {
    close(process->pipeStdOut[0]);
    close(process->pipeStdErr[0]);
    close(process->pipeStdIn[1]);
  }
  //father && error
  if (process->pid > 0 || process->pid == -1) {
    close(process->pipeStdOut[1]);
    close(process->pipeStdErr[1]);
    close(process->pipeStdIn[0]);
  }
  
}

void
d_process_pipe_close(d_process_t *process)
{
  close(process->pipeStdOut[0]);
  close(process->pipeStdOut[1]);
  close(process->pipeStdErr[0]);
  close(process->pipeStdErr[1]);
  close(process->pipeStdIn[0]);
  close(process->pipeStdIn[1]);
}

d_string_t*
d_process_make_args(d_process_t *process)
{
  d_list_iterator_t* iterator;
  d_string_t arg=NULL;
  int i=0;
  d_string_t* args = (d_string_t *)
    malloc((sizeof(char*) * (d_list_length(process->args) + 2)));
  args[i] = process->prog;
  
  for(iterator = d_list_begin(process->args);
      d_list_iterator_valid(iterator);
      d_list_next(&iterator)) {
    d_list_value(iterator, &arg);
    args[++i] = arg;
  }
  args[++i] = NULL;
  
  return args;
}

d_process_t*
d_process_new (d_string_t s_prog)
{
  d_process_t *new = (d_process_t *) malloc(sizeof(d_process_t));
  
  new->pid = -1;
  new->prog = s_prog;
  new->args = NULL;
  new->last_run = -1;
  new->running = d_false;
  
  d_process_pipe_init(new);
  
  return new;
}

d_process_t*
d_process_new_with_args (d_string_t s_prog, d_list_t *args)
{
  d_process_t *new = d_process_new(s_prog);
  
  new->args = args;
  
  return new;
}

void
d_process_free (d_process_t **process) 
{
  if (*process == NULL) return;
  if ((*process)->args != NULL) d_list_free(&((*process)->args));
  free(*process);
  *process = NULL;
}

void
d_process_add_arg (d_process_t *process, d_string_t arg)
{
  if (process->args == NULL) {
    process->args = d_list_new();
  }
  d_list_push(process->args, arg);
}

void
d_process_run (d_process_t *process)
{
  d_string_t *args=NULL;
  
  d_process_pipe_make(process);
  process->last_run = time(NULL);
  process->pid = fork();
  d_process_pipe_close_unused(process);
  
  args = d_process_make_args(process);
  
  //son
  if (process->pid == 0) {
    //cp std io	
    dup2(process->pipeStdOut[1], STDOUT_FILENO);
    dup2(process->pipeStdErr[1], STDERR_FILENO);
    dup2(process->pipeStdIn[0], STDIN_FILENO);
    //make args
    args = d_process_make_args(process);
    //lauch
    execvp(args[0], args);
    
    exit(EXIT_FAILURE);
  }
  //father
  else if (process->pid != -1) {
    process->running = d_true;
  }
}

d_bool_t
d_process_send_signal(d_process_t *process, int signal)
{
  if (kill(process->pid, signal) == -1) {
    return d_false;
  }
  return d_true;
}

int
d_process_wait (d_process_t *process)
{
  int status = EXIT_FAILURE;
  if (process->running) {
    waitpid(process->pid, &status, 0);
    if (WIFEXITED(status)) {
      status = WEXITSTATUS(status);
    }
  }
  return status;
}


d_bool_t
d_process_is_running (d_process_t *process)
{
  return process->running;
}


int
d_process_get_stdout (d_process_t *process)
{
  return process->pipeStdOut[0];
}

int
d_process_get_stderr (d_process_t *process)
{
  return process->pipeStdErr[0];
}

int
d_process_get_stdin (d_process_t *process)
{
  return process->pipeStdIn[1];
}

pid_t
d_process_get_pid (d_process_t *process)
{
  return process->pid;
}

time_t
d_process_get_last_run (d_process_t *process)
{
  return process->last_run;
}

void
d_process_set_prog (d_process_t *process, d_string_t prog)
{
  process->prog = prog;
}

void
d_process_seargs (d_process_t *process, d_list_t *args)
{
  process->args = args;
}
